﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace ImapX.Parsing.Tokens
{
    abstract public class Token
    {
        protected const string SP = @"\s";

        public bool CanBeNIL { get; set; }

        protected Token[] parts;

        public Token(bool canBeNIL = true)
        {
            CanBeNIL = canBeNIL;
        }

        protected virtual string BeginPattern { get { return null; } }
        protected virtual string EndPattern { get { return null; } }

        virtual public string Parse(string input)
        {
            if (CanBeNIL && input.Substring(0, 3) == "NIL") return input.Substring(3);

            input = ParseBegin(input);

            input = ParseParts(input);

            input = ParseEnd(input);

            return input;
        }

        virtual protected string ParseParts(string input)
        {
            if (parts != null)
            {
                if (parts.Length > 1)
                {
                    if (input[0] != '(') throw new ImapException("Missing '(' parsing: " + input);
                    input = input.Substring(1);
                }

                foreach (var part in parts)
                {
                    input = input.TrimStart(' ');
                    input = part.Parse(input);
                }

                if (parts.Length > 1)
                {
                    if (input[0] != ')') throw new ImapException("Missing '(' parsing: " + input);
                    input = input.Substring(1);
                }
            }
            return input;
        }

        protected virtual string ParseBegin(string input)
        {
            if (BeginPattern != null)
            {
                Match m = Match(input, BeginPattern);

                if (!m.Success) throw new ImapException("Failed to parse token, " + this.GetType().FullName + " from '" + input + "'");

                input = input.Substring(m.Length);
            }

            return input;
        }

        protected virtual string ParseEnd(string input)
        {
            if (EndPattern != null)
            {
                Match m = Match(input, EndPattern);

                if (!m.Success) throw new ImapException("Failed to parse end of token, " + this.GetType().FullName + " from '" + input + "'");

                input = input.Substring(m.Length);
            }

            return input;
        }

        protected void SetParts(params Token[] parts)
        {
            this.parts = parts;
        }

        protected Match Match(string input, string pattern)
        {
            return Regex.Match(input, @"\A" + pattern);
        }

        protected bool IsMatch(string input, string pattern)
        {
            return Regex.IsMatch(input, @"\A" + pattern);
        }
    }
}
